/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2009 Philippe Durand <draekz@gmail.com>
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Collections.Generic;
using System.Security.Cryptography;

using Galaxium.Core;

using Anculus.Core;

namespace Galaxium.Protocol.Facebook
{
	public class FBConnection : AbstractConnection
	{
		private CookieCollection _savedCookies;
		
		private bool _loggedIn = false;
		
		private string _formID = String.Empty;
		private string _channelID = String.Empty;
		private int _fetchID = 0;
		
		private System.Timers.Timer _buddyTimer = new System.Timers.Timer(60*1000);
		private System.Timers.Timer _requestTimer = new System.Timers.Timer(60*5*1000);
		private System.Timers.Timer _notificationTimer = new System.Timers.Timer(60*1000);
		private System.Timers.Timer _messageTimer = new System.Timers.Timer (10*1000);
		
		public override bool IsConnected
		{
			get
			{
				return _loggedIn;
			}
		}
		
		public override bool IsSending
		{
			get
			{
				throw new System.NotImplementedException ();
			}
		}
		
		internal string FormID
		{
			get { return _formID; }
			set { _formID = value; }
		}
		
		internal string ChannelID
		{
			get { return _channelID; }
			set { _channelID = value; }
		}
		
		internal int FetchID
		{
			get { return _fetchID; }
			set { _fetchID = value; }
		}
		
		internal CookieCollection SavedCookies
		{
			get
			{
				return _savedCookies;
			}
		}
		
		public FBConnection(FBSession session) : base (session, new FBConnectionInfo("www.facebook.com"))
		{
			_savedCookies = new CookieCollection ();
			
			_buddyTimer.AutoReset = true;
			_buddyTimer.Elapsed += UpdateBuddyList;
			_buddyTimer.Enabled = false;
			
			_requestTimer.AutoReset = true;
			_requestTimer.Elapsed += UpdateFriends;
			_requestTimer.Enabled = false;
			
			_notificationTimer.AutoReset = true;
			_notificationTimer.Elapsed += UpdateNotifications;
			_notificationTimer.Enabled = false;
			
			_messageTimer.AutoReset = true;
			_messageTimer.Elapsed += UpdateMessages;
			_messageTimer.Enabled = false;
		}
		
		void UpdateBuddyList (object obj, System.Timers.ElapsedEventArgs args)
		{
			BuddyListRequest request = new BuddyListRequest (this);
			request.Completed += BuddyListCompleted;
			request.Failed += BuddyListFailed;
			request.EntityImage += BuddyListEntityImage;
			
			request.Begin ();
		}
		
		void UpdateFriends (object obj, System.Timers.ElapsedEventArgs args)
		{
			
		}
		
		void UpdateMessages (object obj, System.Timers.ElapsedEventArgs args)
		{
			
		}
		
		void UpdateNotifications (object obj, System.Timers.ElapsedEventArgs args)
		{
			
		}
		
		internal void UpdateStatus (string message, double percent)
		{
			var args = new SessionProgressEventArgs (Session, message, percent);
			ThreadUtility.Dispatch (() => (Session as FBSession).EmitLoginProgress (args));
		}
		
		public override void Connect ()
		{
			UpdateStatus ("Connecting...", 0.0);
			
			_loggedIn = false;
			
			LoginRequest request = new LoginRequest (this);
			request.Failed += LoginFailed;
			request.Completed += LoginComplete;
			
			UpdateStatus ("Authenticating...", 0.25);
			
			request.Begin ();
		}
		
		public override void Disconnect ()
		{
			_loggedIn = false;
		}
		
		public override void Reconnect ()
		{
			Disconnect ();
			Connect ();
		}
		
		private void PerformSessionStart ()
		{
			// Now we are fully logged in. We should check for friends, messages and notifications.
			_messageTimer.Enabled = true;
			_buddyTimer.Enabled = true;
			_notificationTimer.Enabled = true;
			_requestTimer.Enabled = true;
		}
		
		private void LoginFailed (object obj, RequestErrorEventArgs args)
		{
			var errorArgs = new ErrorEventArgs (Session, "Login Failed", args.Message);
			ThreadUtility.Dispatch (() => (Session as FBSession).EmitErrorOccurred (errorArgs));
		}
		
		private void LoginComplete (object obj, EventArgs args)
		{
			UpdateStatus ("Synchronizing...", 0.50);
			
			BuddyListRequest request = new BuddyListRequest (this);
			request.Completed += BuddyListCompleted;
			request.Failed += BuddyListFailed;
			request.EntityImage += BuddyListEntityImage;
			
			request.Begin ();
		}
		
		private void BuddyListEntityImage (object obj, RequestEntityImageArgs args)
		{
			var eargs = new EntityChangeEventArgs<IDisplayImage> (args.Entity, args.Entity.DisplayImage, args.OldImage);
			ThreadUtility.Dispatch (() => (Session as FBSession).EmitContactDisplayImageChanged (eargs));
		}
		
		private void BuddyListFailed (object obj, RequestErrorEventArgs args)
		{
			if (!_loggedIn)
			{
				var errorArgs = new ErrorEventArgs (Session, "Login Failed", args.Message);
				ThreadUtility.Dispatch (() => (Session as FBSession).EmitErrorOccurred (errorArgs));
			}
		}
		
		private void BuddyListCompleted (object obj, EventArgs args)
		{
			if (!_loggedIn)
			{
				UpdateStatus ("Configuring...", 0.75);
				
				SettingsRequest request = new SettingsRequest (this);
				request.Failed += SettingsFailed;
				request.Completed += SettingsCompleted;
				request.Begin ();
			}
		}
		
		private void SettingsFailed (object obj, RequestErrorEventArgs args)
		{
			var errorArgs = new ErrorEventArgs (Session, "Login Failed", args.Message);
			ThreadUtility.Dispatch (() => (Session as FBSession).EmitErrorOccurred (errorArgs));
		}
		
		private void SettingsCompleted (object obj, EventArgs args)
		{
			// Once we have obtained the settings, we have to set presence.
			PresenceRequest request = new PresenceRequest (this);
			request.Completed += PresenceCompleted;
			request.Failed += PresenceFailed;
			request.Begin ();
		}
		
		private void PresenceFailed (object obj, RequestErrorEventArgs args)
		{
			var errorArgs = new ErrorEventArgs (Session, "Login Failed", args.Message);
			ThreadUtility.Dispatch (() => (Session as FBSession).EmitErrorOccurred (errorArgs));
		}
		
		private void PresenceCompleted (object obj, EventArgs args)
		{
			UpdateStatus ("Done!", 1.0);
			
			if (!_loggedIn)
				_loggedIn = true;
			
			var eargs = new SessionEventArgs (Session);
			ThreadUtility.Dispatch (() => (Session as FBSession).EmitLoginCompleted (eargs));
			
			PerformSessionStart ();
		}
	}
}
